#include "CServer.hpp"
#include "AsioIoContextPool.hpp"
#include "RedisMgr.hpp"
#include "UserMgr.hpp"
#include "const.hpp"
#include <boost/asio/ip/tcp.hpp>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
CServer::CServer(boost::asio::io_context &io_context, short port)
    : _ioc_context(io_context), _port(port),
      _acceptor(io_context, boost::asio::ip::tcp::endpoint(
                                boost::asio::ip::tcp::v4(), _port)) {
  std::cout << "Server start success, listen on port : " << _port << std::endl;
  StartAccept();
}

CServer::~CServer() {
  {
    std::lock_guard<std::mutex> lock(_mutex);
    _sessions.clear();
  }
  std::cout << "Server destruct listen on port : " << _port << std::endl;
}

void CServer::HandleAccept(std::shared_ptr<CSession> sessoin,
                           const boost::system::error_code &ec) {
  if (!ec) {
    sessoin->Start();
    std::lock_guard<std::mutex> lock(_mutex);
    // 记录对话
    _sessions.insert(std::make_pair(sessoin->GetSessionId(), sessoin));
  } else {
    std::cout << "session accept failed, error is " << ec.message()
              << std::endl;
  }
  StartAccept();
}

void CServer::StartAccept() {
  auto &io_context = AsioIoContextPool::GetInstance().GetIoContext();
  std::shared_ptr<CSession> session =
      std::make_shared<CSession>(io_context, this);
  _acceptor.async_accept(
      session->GetSocket(),
      std::bind(&CServer::HandleAccept, this, session, std::placeholders::_1));
}

void CServer::ClearSession(std::string sessionId) {
  // 清除用户与session的绑定
  if (_sessions.find(sessionId) != _sessions.end()) {
    UserMgr::GetInstance().RemoveUserSession(_sessions[sessionId]->GetUserId());
  }
  std::unique_lock<std::mutex> lock(_mutex);
  _sessions.erase(sessionId);
  unsigned long loginCount = _sessions.size();
  lock.unlock();
  // 更新Redis中该服务器登录人数
  std::string server_name = config.get<std::string>("SelfServer.Name");
  RedisMgr::GetInstance().HSet(LOGIN_COUNT, server_name,
                               std::to_string(loginCount));
}